/*
 * @Title: 标题
 * @Description: 描述
 * @FilePath: /src/utils/render.ts
 */
export interface IRenderConfig {
  /**
   * 原始内容根节点id
   */
  container?: string
  /**
   * 渲染好的pdf内容挂载节点id
   */
  pdfContainer?: string
  /**
   * 纸张大小
   */
  pageSize?: string
  /**
   * 纸张朝向，可选值：portrait（纵向），landscape（横向）
   */
  orientation?: string
  /**
   * 自定义内容大小，将自动缩放到对应的pageSize
   */
  pageSizeOptions?: {
    /**
     * 每英寸像素
     */
    dpi?: number
    /**
     * 自定义宽度，单位px
     */
    width?: string
    /**
     * 自定义高度，单位px
     */
    height?: string
  }
  /**
   * 页面边距
   */
  padding?: string
}

export interface INodeAttrs {
  class?: string
  id?: string
  style?: string
  'data-op-type'?: string
  'data-op-pager'?: number
}

export interface INode {
  /**
   * 节点标签
   */
  tag: string
  /**
   * 节点属性
   */
  attrs?: INodeAttrs
  /**
   * 子节点列表
   */
  children?: INode[] | Element[]
}

export interface ICreatePage {
  pdfRoot: Element
  pageNumber: number
  style?: string
  padding?: string
  content?: Element[]
}

/**
 * 页面尺寸大全
 */
const PAGE_SIZES: {
  [key: string]: {
    [key: string]: string[]
  }
} = {
  A4: {
    portrait: ['210mm', '297mm'],
    landscape: ['297mm', '210mm']
  }
}

/**
 * 创建单个节点
 * @param tag 节点标签
 * @param attrs 节点属性
 * @returns
 */
const createNode = (param: INode): Element => {
  const Node: Element = document.createElement(param.tag)
  if (param.attrs) {
    Object.entries(param.attrs).forEach((el) => {
      const [name, value] = el
      Node.setAttribute(name, value)
    })
  }
  if (Array.isArray(param.children)) {
    param.children.forEach((child) => {
      if (child instanceof Element) {
        Node.append(child)
      } else {
        Node.append(createNode(child as INode))
      }
    })
  }
  return Node
}

/**
 * 创建分页容器，并返回下一个分页页码
 */
const createPage = ({ pdfRoot, pageNumber, style, padding, content }: ICreatePage): void => {
  if (!pdfRoot || !(pdfRoot instanceof Element)) {
    throw new Error('Error: 请传入pdf根节点')
  }
  // 创建分页盒子
  const page = createNode({
    tag: 'div',
    attrs: {
      class: 'pdf-page-item',
      'data-op-pager': pageNumber,
      style
    },
    children: [
      {
        tag: 'div',
        attrs: {
          class: 'pdf-page-box',
          style: `padding:${padding}`
        },
        children: [
          {
            tag: 'div',
            attrs: {
              class: 'pdf-page-content'
            },
            children: content ? content : undefined
          }
        ]
      }
    ]
  })
  // 将分页插入pdf根节点
  pdfRoot.append(page)
}
/**
 * 将节点推入分页
 * @param pdfRoot
 * @param El
 * @param config
 */
const pushElToPage = (pdfRoot: Element, El: Element, config: IRenderConfig) => {
  const { pageSize = 'A4', orientation = 'portrait', padding = '100px 100px 50px 100px' } = config
  // 设置分页大小样式
  const pageStyle = `width:${PAGE_SIZES[pageSize][orientation][0]};height:${PAGE_SIZES[pageSize][orientation][1]}`
  // 获取分页高度（像素）
  const pageHeight = 1123
  // 若pdf容器不包含任何子节点（分页），则创建一个分页以避免后续动作查询部到pdf容器内的最后一页
  if (!pdfRoot.children.length) {
    createPage({ pdfRoot, pageNumber: 1, style: pageStyle, padding })
  }
  // 查找pdf最后一页
  const lastPage: Element = pdfRoot.children.item(pdfRoot.children.length - 1)!
  // 页码自增
  const pageNumber = lastPage.getAttribute('data-op-pager')
    ? Number(lastPage.getAttribute('data-op-pager'))
    : 1
  // 获取将要插入的节点
  const pageBox = lastPage.querySelector('div.pdf-page-box')
  const targetNode = pageBox!.querySelector('div.pdf-page-content')
  // 分页盒模型剩余空间
  const surplus = pageBox!.clientHeight - targetNode!.clientHeight
  console.log('分页盒模型剩余空间', surplus)
  // 插入节点高度小于剩余空间，则直接插入，否则进行代码分割
  if (surplus > El.clientHeight) {
    targetNode!.append(El)
  } else {
    createPage({ pdfRoot, pageNumber: pageNumber + 1, style: pageStyle, content: [El] })
  }
  console.log('分页盒模型剩余空间', surplus)
}

/**
 * 渲染pdf
 * @param id 源内容根节点
 * @param config pdf页面配置
 */
export function render(config: IRenderConfig = {}) {
  const { container = 'content-box', pdfContainer = 'pdf-container' } = config
  // pdf挂载节点
  const pdfRoot: Element = document.getElementById(pdfContainer)
    ? document.getElementById(pdfContainer)!
    : createNode({
        tag: 'div',
        attrs: {
          class: 'pdf-container',
          id: pdfContainer
        }
      })
  document.getElementById('pdf-box')?.append(pdfRoot)
  // 获取原始内容根节点
  const root: Element | null = document.querySelector('#' + container)
  // 循环处理原始内容直接子节点
  if (root?.children && root.children.length) {
    Array.from(root.children).forEach((child: Element) => {
      pushElToPage(pdfRoot, child, config)
    })
  }
}
